package com.start.common.utils;


import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.start.common.model.TreeModel;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

public class TreeModelUtils {


    public static <T extends TreeModel<T>> List<T> createTree(List<T> models) {
        return createTree(models, null, true);
    }

    public static <T extends TreeModel<T>> List<T> createTree(List<T> models, boolean containRoot) {
        return createTree(models, null, containRoot);
    }

    /**
     * @param models      待转换成树结构的数据
     * @param rootIds     root节点id
     * @param containRoot 是否保护root 节点
     * @param <T>
     * @return
     */
    public static <T extends TreeModel<T>> List<T> createTree(List<T> models, Collection<String> rootIds, boolean containRoot) {
        List<T> treeModels = new ArrayList<>();
        if (models == null || models.isEmpty()) return treeModels;
        List<T> rootNodes = findAllRootNodes(models, rootIds);
        Map<String, List<T>> listMap = models.stream().collect(Collectors.groupingBy(T::getParentId));
        for (T model : models) {
            List<T> children = listMap.get(model.getParentId());
            model.setChildren(children);
        }
        if (!containRoot) {
            return rootNodes;
        }
        for (T model : rootNodes) {
            if (model.getChildren() == null || model.getChildren().isEmpty()) {
                continue;
            }
            List<T> children = model.getChildren();
            treeModels.addAll(children);
        }

        return treeModels;
    }


    /**
     * 查找全部父级
     *
     * @param models
     * @return
     */
    private static <T extends TreeModel> List<T> findAllRootNodes(List<T> models, Collection<String> rootIds) {
        if (models.isEmpty()) return new ArrayList<>();
        if (rootIds != null && !rootIds.isEmpty()) {
            return models.stream().filter(e -> rootIds.contains(e.getId())).collect(Collectors.toList());
        }
        List<T> rootNodes = new ArrayList<>();
        Map<String, T> dicMap = new HashMap<>();
        for (T model : models) {
            if (StringUtils.isEmpty(model.getId())) continue;
            if (dicMap.containsKey(model.getId())) continue;
            dicMap.put(model.getId(), model);
        }
        for (T model : models) {
            if (StringUtils.isNotEmpty(model.getParentId()) && dicMap.containsKey(model.getParentId())) {
                continue;
            }
            rootNodes.add(model);
        }
        return rootNodes;
    }

    /**
     * 查找当前节点的全部父级节点
     *
     * @param models
     * @param nodeId
     * @param <T>
     * @return
     */
    public static <T extends TreeModel> List<T> findParentModels(List<T> models, String nodeId) {
        if (models == null || models.isEmpty()) return new ArrayList<>();
        if (StringUtils.isEmpty(nodeId)) return new ArrayList<>();
        List<T> modelNodes = models.stream().filter(e -> e.getId().equals(nodeId)).toList();
        if (modelNodes.isEmpty()) return new ArrayList<>();
        T tempNode = modelNodes.get(0);
        return findParentModels(models, tempNode);
    }

    public static <T extends TreeModel> List<T> findParentModels(List<T> models, T node) {
        if (node == null) return new ArrayList<>();
        T tempNode = node;
        List<T> parentNodes = new ArrayList<>();
        while (StringUtils.isNotEmpty(tempNode.getParentId())) {
            T finalTempNode = tempNode;
            List<T> tempNodesTemp = models.stream().filter(e -> e.getId().equals(finalTempNode.getParentId())).toList();
            if (tempNodesTemp.isEmpty()) break;
            tempNode = tempNodesTemp.get(0);
            parentNodes.add(tempNode);
        }
        Collections.reverse(parentNodes);
        return parentNodes;
    }


    public static JSONArray treeToList(JSONArray array) {
        return treeToList(array, "id", "parentId", "children", null);
    }

    /**
     * json 树型结构数据转数组
     *
     * @param array
     * @param valueKey
     * @param childrenKey
     * @param parentKey
     * @return
     */
    public static JSONArray treeToList(JSONArray array, String valueKey, String parentKey, String childrenKey, String parentId) {
        JSONArray result = new JSONArray();
        treeToList(array, valueKey, parentKey, childrenKey, parentId, result::add);
        return result;
    }

    /**
     * json 树型结构数据转数组
     *
     * @param array
     * @param valueKey
     * @param childrenKey
     * @param parentKey
     * @param parentId
     * @param callBack
     */
    public static void treeToList(JSONArray array, String valueKey, String parentKey, String childrenKey, String parentId, TreeDataFindChildrenItem<JSONObject> callBack) {
        if (array.isEmpty()) return;
        valueKey = StringUtils.isEmpty(valueKey) ? "id" : valueKey;
        childrenKey = StringUtils.isEmpty(childrenKey) ? "children" : childrenKey;
        parentKey = StringUtils.isEmpty(parentKey) ? "parentKey" : parentKey;

        for (int i = 0; i < array.size(); i++) {
            JSONObject item = array.getJSONObject(i);
            callBack.findItem(item);
            if (!StringUtils.isEmpty(parentId) && !item.containsKey(parentKey)) {
                item.put(parentKey, parentId);
            }
            if (!item.containsKey(childrenKey)) {
                continue;
            }
            JSONArray childrenArray = item.getJSONArray(childrenKey);
            if (childrenArray.isEmpty()) {
                continue;
            }
            treeToList(childrenArray, valueKey, childrenKey, parentKey, item.getString(valueKey), callBack);
        }

    }

    public interface TreeDataFindChildrenItem<T> {
        void findItem(T item);
    }

}
